//
//  Server.swift
//  SerViceTest
//
//  Created by 薛永伟 on 2019/5/14.
//  Copyright © 2019 Yuri. All rights reserved.
//

import Foundation
import Alamofire
import SwiftyJSON


/// 服务器
class API:NSObject {
    
    /// 请求完毕
    typealias CompleteBlock = (_ response:Response)->()
    
    /// 远程服务出错
    struct ServiceError:Error,LocalizedError,Decodable {
        var code:Int
        var errorMessage:String
    }
    
    /// 回应数据
    struct Response:Decodable {
        
        /// 需要解析的数据
        var data:JSON?
        /// 已约定：status为1才没有error，否则就会有error信息
        var status:Int = 0
        /// 错误信息
        var error:ServiceError?
    }
    
    /// 数据可达
    struct Reachability {
        
        
        private static var manager = NetworkReachabilityManager.init()
        
        static func startListening(){
            manager?.startListening()
        }
        
        static var isReachable:Bool {
            let result = manager?.isReachable ?? false
            return result
        }
        
        /// 信任所有证书信任询问
        static func trustAllChallenge(){
            
            SessionManager.default.delegate.sessionDidReceiveChallenge = { session,challenge in
                
                return (URLSession.AuthChallengeDisposition.useCredential,URLCredential(trust:challenge.protectionSpace.serverTrust!))
            }
        }
    }
    
    /// 运行环境
    enum Environment:Int{
        
        case develop = -1    //开发环境
        case gray = 1       //灰度环境
        case release = 0    //生产环境
        
        /// 当前的运行环境
        static var current:Environment {
            
//            return .develop
            
            let stateInt = Preference.Develop.APIEnvironment.int
            //默认release环境，保底显示线上数据
            let evironment = Environment.init(rawValue: stateInt) ?? .release
            return evironment
        }
    }
    
    /// 协议
    static var urlProtocol: String = {
        
        if Environment.current == .develop {
            return "http"
        }
        return "https"
    }()
    
    /// 域名
    static func Domain() ->String{
        
        switch Environment.current {
        case .develop:
            return "114larc.com"
        case .gray:
            return "114la.com"
        case .release:
            return "114la.com"
        }
    }
    
    /// 静态资源域名
    static func ResourceDomain() ->String {
        
        return "114la.com"
    }
}



//MARK: - --------------APIUrlable--------------
protocol APIUrlable:NSObjectProtocol {
    
    /// 协议的规定url方法，正确拼接出当前模块的url路径
    static func Base_URL() -> String
}

extension APIUrlable {
    
    /// 创建给定路径的url，path需包含前缀"/xx"
    static func urlWithPath(_ path:String) -> URL {
        
        let urlstr = Base_URL() + path
        if let url = URL.init(string: urlstr) {
            return url
        }else{
            assertionFailure("不能创建URL:\(urlstr)!")
            return URL.init(string: urlstr)!
        }
    }
}

extension API:APIUrlable {
    
    /// Base_URl
    static func Base_URL() -> String {
        
        if Environment.current == .develop {
            return "\(urlProtocol)://\(Domain())"
        }
        return "\(urlProtocol)://\(Domain())"
    }
}



//MARK: - --------------发起请求--------------
extension API{
    
    @discardableResult
    static func request(_ url: URLConvertible,
                        method:HTTPMethod = .post,
                        headers:HTTPHeaders? = nil,
                        parameters: Parameters? = nil
        ) -> DataRequest{
        
        var headers:HTTPHeaders? = headers
        
        if let user = User.current {
            headers = ["XX-Token":user.token,"XX-Device-Type":"iphone"]
        }
        
        YRLog("发起请求:\(url)\n\(parameters?.description ?? "无参数")\n")
        return SessionManager.default.request(
            url,
            method: method,
            parameters: parameters,
            encoding: URLEncoding.default,
            headers: headers
        )
    }
    
    static func upload(data:Data,to url:URL,method:HTTPMethod,headers:HTTPHeaders?) -> UploadRequest {
        
        return SessionManager.default.upload(data, to: url, method: method, headers: headers)
    }
    
    /// 上传file图片，和其他参数
    static func uploadPictures(_ url: URLConvertible,
                               method:HTTPMethod = .post,
                               parameters: [String:String]? = nil,
                               headers:HTTPHeaders? = nil,
                               pictures:[UIImage],
                               pictureNames:[String],
                               complete:@escaping (SessionManager.MultipartFormDataEncodingResult)->()) {
        
        
        SessionManager.default.upload(multipartFormData: { (formData) in
            
            for (idx,pic) in pictures.enumerated() {
                if let picData = pic.compressImageOnlength(maxLength: 500){
                    formData.append(picData, withName: pictureNames[idx], fileName: "pic\(idx).jpg", mimeType: "image/jpeg")
                }
            }
            
            if let params = parameters {
                for (key,value) in params {
                    if let valueData = value.data(using: String.Encoding.utf8){
                        formData.append(valueData, withName: key)
                    }
                }
            }
        }, to: url, method:method , headers: headers) { (formDataEncodingResult) in
            
            complete(formDataEncodingResult)
            
        }
        
    }
    
}



//MARK: - --------------回应Response--------------
extension DataRequest {
    
    /// 格式化后的回应
    @discardableResult
    func formattedResponse(sucessCode:Int? = nil, complete:@escaping API.CompleteBlock) -> Self {
        
        let requestLog = "->请求:\(request?.url?.absoluteString ?? "空的")"
        
        let header = request?.urlRequest?.allHTTPHeaderFields?.description ?? "null"
        print(header)
        
        
        let res = responseJSON { (response) in
            
            if let token = response.response?.allHeaderFields["x-auth-token"] as? String {
                YRLog("得到token:\(token)", type: .info)
                API.Cookie.addTokenCookie(token: token, in: response.response?.url)
            }
            
            switch response.result{
            case .success(let value):
                let json = JSON(value)
                
                YRLog("\(requestLog)\n  成功:\n \(json) \n<-\n", type: .info)
                
                let status = json["status"].intValue
                
                // 是否有错误
                var error:API.ServiceError? = nil
                
                if let sucessCode = sucessCode,
                    status != sucessCode {
                    let message = json["message"].string ?? "Error"
                    let errorMessage = json["errorMessage"].string ?? message
                    let errCode = json["errCode"].intValue
                    error = API.ServiceError.init(code: errCode, errorMessage: errorMessage)
                }
                
//                if let errCode = error?.code, errCode == 1000003 {//无效授权用户
//                    MBProgressHUD.showText(error?.localizedDescription ?? "需要重新登录")
//                    Auth.User.current?.logOut()
//                    return
//                }
                // 数据
                let data = json["data"]
                
                let response = API.Response.init(data: data, status: status, error: error)
                complete(response)
                
                
                
                break
            case .failure(let error):
                
                let nserror = error as NSError
                
                var error = API.ServiceError.init(code: nserror.code, errorMessage: nserror.localizedDescription)
                if error.code == -1009 {
                    error.errorMessage = "网络连接状态异常，请检查"
                }
                
                YRLog("\(requestLog)\n 失败:\n \(error.localizedDescription) \n<-\n", type: .info)
                
                let response = API.Response.init(data: nil, status: 0, error: error)
                complete(response)
                break
            }
        }
        return res
    }
    
}



//MARK: - --------------cookie--------------
extension API {
    
    /// cookie相关
    struct Cookie {
        
        /// 把server返回的cookie更新到本地
        static func updateCookies(response: DataResponse<Any>){
            
            let headerFields = response.response?.allHeaderFields as! [String: String]
            let url = response.request?.url
            
            let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url!)
            
            var cookieArray = [ [HTTPCookiePropertyKey : Any ] ]()
            for cookie in cookies {
                cookieArray.append(cookie.properties!)
            }
            
            UserDefaults.standard.set(cookieArray, forKey: "server_tokens")
        }
        
        /// 恢复保存的cookies，理论上不需要自行处理
        static func restoreCookies(){
            
            if let cookieArray = UserDefaults.standard.array(forKey: "server_tokens") {
                for cookieData in cookieArray {
                    if let dict = cookieData as? [HTTPCookiePropertyKey : Any] {
                        if let cookie = HTTPCookie.init(properties : dict) {
                            HTTPCookieStorage.shared.setCookie(cookie)
                        }
                    }
                }
            }
        }
        
        /// t恢复token到cookie中
        static func restoreTokenCooike(){
            
            if let token = Preference.User.TokenAuth.string {
                addTokenCookie(token: token, in: nil)
            }else{
                YRLog("没有能恢复的token", type: .warning)
            }
        }
        
        /// 把token添加到cookie里
        static func addTokenCookie(token:String,
                                   in url:URL?){
            
            var cookieProperties = [HTTPCookiePropertyKey: String]()
            cookieProperties[HTTPCookiePropertyKey.name] = "x-auth-token"
            cookieProperties[HTTPCookiePropertyKey.value] = token
            cookieProperties[HTTPCookiePropertyKey.domain] = url?.host ?? API.Domain()
            cookieProperties[HTTPCookiePropertyKey.path] = "/"
            if let tokenCookie = HTTPCookie(properties: cookieProperties){
                HTTPCookieStorage.shared.setCookie(tokenCookie)
                Preference.User.TokenAuth.setValue(any: token)
            }else{
                YRLog("无法创建token的scookie:\(token)", type: .error)
            }
        }
        
        
        /// 清理token
        static func clearToken(){
            
            if let cookies = HTTPCookieStorage.shared.cookies?.enumerated(){
                for (_,cookie) in  cookies{
                    if cookie.domain == API.Domain() {
                        HTTPCookieStorage.shared.deleteCookie(cookie)
                    }
                }
            }
        }
    }
}

